// ThinLensCamera
/*
We generate rays according to the two principles of thin lens.
#1. A ray through focal point of lens becomes parallel after hitting the lens
#2. A ray parallel to the lens passes through the focal point of the lens on the other side

So essentially we will generate two rays first to determine the point of intersection of the two rays among themselves and then we direct all rays in the lens towards this point
Then we will generate rays from all sample points on the lens to the particular point.
*/

#include "Camera.h"

/*
Function	: Constructor - Explicit Initialization
Params		: None
Return Type : None	
Desc		: Constructor
*/
ThinLensCamera::ThinLensCamera(Vector3 _pos, Vector3 _dir, Vector3 _up, Handedness hand, int iw, int ih, int pixels_x, int pixels_y, float image_dist, float radius, float focal_back, float focal_front)
{
	// Initialize all attributes of the camera
	position = _pos;
	direction = _dir;
	up = _up;

	// Initialize the image attributes
	image_width = iw;
	image_height = ih;
	npixels_x = pixels_x;							// horizontal resolution supported by the film
	npixels_y = pixels_y;							// vertical resolution supported by the film
	pixel_x_offset = float(image_width/npixels_x);
	pixel_y_offset = float(image_height/npixels_y);
	image_distance = image_dist;					// actual distance of film from the lens

	// lens attributes
	lens_radius = radius;
	Fb = focal_back;
	Ff = focal_front;
	
	// Set up the coordinate spaces of the camera and the image plane
	camera_coord.v = up.GetNormalizedVector();
	camera_coord.w = direction.GetNormalizedVector();
	camera_coord.ConstructFromVW(this->camera_coord.v, this->camera_coord.w);

	// Compute focal points
	focalpoint_f = position + (camera_coord.w * Ff);
	focalpoint_b = position - (camera_coord.w * -Fb);	

	// Computer principal plane
	// Normal is dependant on handedness - assuming left handed ness
	// Hence normal is opposite of w - (look direction)
	principal_plane = Plane(position, -camera_coord.w);
	
	// Image plane coord
	// Assuming the image plane to be centered around the view direction
	image_origin = Vector3(position.x - iw/2, position.y - ih/2, position.z - image_distance);	// assuming per pixel width is 1.0f
	image_u = camera_coord.u;
	image_v = camera_coord.v;
}

/*
Function	: GetRay
Params		: @1 - Pixel (x) location
			  @2 - Pixel (y) location
Return type	: Ray3
Desc		: Get a ray from the pixel coords(x,y) into the scene. This method is similar to pin hole camera
			  
*/
Ray3 ThinLensCamera::GetRay(int pixel_x, int pixel_y)
{
	//Calculate the ray origin of all samples
	Vector3 origin = image_origin + (image_u*pixel_x*pixel_x_offset) + (image_v*pixel_y*pixel_y_offset);
	Vector3 direction = position - origin;
	direction.Normalize();
	return Ray3(origin, direction);
}

/*
Function	: GetRay
Params		: @1 - Pixel(x) location
			  @2 - Pixel(y) location
			  @3 - number of samples
Return type	: RayPacket
Desc		: This function calculates a number of rays from the lens surface for particular pixel(x,y) based on samples number
*/
/*
RayPacket ThinLensCamera::GetRay(int pixel_x, int pixel_y, int num_samples)
{
	// Initialize the ray packet structure
	RayPacket pkt;
	pkt.pRays = new Ray3[num_samples];
	pkt.n_rays = num_samples;

	// Find the actual focussed point due to lens
	// This is found out by shooting a ray from pixel coords to principal plane parallel to optic axis
	// Another ray through center of the lens
	// The two rays would intersect at a point. All rays from the lens that correspond to a particular pixel intersect at that point
	Vector3 focussed_point;
	Vector3 origin = image_origin + (image_u*pixel_x*pixel_x_offset) + (image_v*pixel_y*pixel_y_offset);	// image plane
	Ray3 optic_axis_parallel_ray(origin, camera_coord.w);
	Ray3 lens_center_ray(origin, Vector3(position-origin).GetNormalizedVector());
	

	// We use a sampler to generate samples in the range [-lens_radius , lens_radius] on the surface of the lens
}
*/
